﻿Imports System.Data
Imports System.Windows.Controls
Imports System.Windows.Media
Imports System.Windows.Input
Imports System.Windows

Namespace Grids

    Public Class FastGridControl
        Inherits Canvas

        Dim _VerticalScroll As Integer
        Dim _HorizontalScroll As Integer


        Sub New()
            DefaultCursor = Cursor
            editingTextBox = New TextBox() With {
                .HorizontalAlignment = Windows.HorizontalAlignment.Left,
                .VerticalAlignment = Windows.VerticalAlignment.Top,
                .Width = DefaultWidth - 2,
                .Height = DefaultHeight - 2}
            Canvas.SetTop(editingTextBox, 0.0)
            Canvas.SetLeft(editingTextBox, 0.0)
            editingTextBox.Visibility = Windows.Visibility.Collapsed
            editingTextBox.BorderThickness = New Thickness(0)
            AddHandler editingTextBox.LostFocus, AddressOf editingTextBoxLostFocus
            AddHandler editingTextBox.KeyDown, AddressOf editingTextBoxKeyDown
            Children.Add(editingTextBox)

            ContextMenu = New ContextMenu()
            Dim m1 = New MenuItem() With {.Header = "Format"}
            ContextMenu.Items.Add(m1)
            ContextMenu.Items.Add(New MenuItem() With {.Header = "Copier"})
            ContextMenu.Items.Add(New MenuItem() With {.Header = "Coller"})
            'AddHandler m1.Click, AddressOf FormatClick
        End Sub
        Private DefaultCursor As Cursor
        Private editingTextBox As TextBox
        Public Shared DefaultHeight As Double = 20
        Public Shared DefaultWidth As Double = 125
        Public Shared DefaultFirstRowHeight As Double = 20
        Public Shared DefaultFirstColumnWidth As Double = 20
        Public Shared DefaultBrush As Brush = Brushes.Black

        Protected Overrides Sub OnRender(ByVal drawingContext As System.Windows.Media.DrawingContext)

            MyBase.OnRender(drawingContext)

            Dim maxcols = CInt(ActualWidth / DefaultWidth) + 1
            Dim maxrows = CInt(ActualHeight / DefaultHeight) + 1

            Dim x = Math.Floor(Math.Min(Current.X, Last.X) / DefaultWidth)
            Dim y = Math.Floor(Math.Min(Current.Y, Last.Y) / DefaultHeight)
            Dim x2 = Math.Floor(Math.Max(Current.X, Last.X) / DefaultWidth) + 1
            Dim y2 = Math.Floor(Math.Max(Current.Y, Last.Y) / DefaultHeight) + 1


            drawingContext.PushClip( _
                New RectangleGeometry( _
                    New Rect(1, 1, ActualWidth - 1, ActualHeight - 1)))

            For Each r In ranges
                If r.Brush IsNot Nothing Then
                    drawingContext.DrawRectangle( _
                        r.Brush, _
                        Nothing, _
                New Rect((r.Column - HorizontalScroll) * DefaultWidth, (r.Row - VerticalScroll) * DefaultHeight, _
                         r.ColumnCount * DefaultWidth, r.RowCount * DefaultHeight))
                End If
            Next

            drawingContext.DrawRectangle( _
                Brushes.Aqua, _
                Nothing, _
                New Rect(x * DefaultWidth, y * DefaultHeight, _
                         (x2 - x) * DefaultWidth, (y2 - y) * DefaultHeight))


            'For i = 1 To maxcols
            '    drawingContext.DrawLine( _
            '        New Pen(DefaultBrush, 1.0), _
            '        New Point(i * DefaultWidth, 0), _
            '        New Point(i * DefaultWidth, ActualHeight))
            'Next
            'For i = 1 To maxrows
            '    drawingContext.DrawLine( _
            '        New Pen(DefaultBrush, 1.0), _
            '        New Point(0, i * DefaultHeight), _
            '        New Point(ActualWidth, i * DefaultHeight))
            'Next


            For Each r In ranges
                'For i = 1 To r.RowCount
                '    For j = 1 To r.ColumnCount
                '        drawingContext.DrawText( _
                '            GetFormattedText( _
                '                If(r(i, j) Is Nothing, "", r(i, j).ToString())), _
                '             New Point((r.Column + j - 1) * DefaultWidth, (r.Row + i - 1) * DefaultHeight))
                '    Next
                'Next
                'If r.Brush IsNot Nothing Then

                'End If
            Next

            If Data IsNot Nothing Then
                For j = Math.Min(Data.Table.Columns.Count - 1, HorizontalScroll) To Math.Min(Data.Table.Columns.Count - 1, maxcols + HorizontalScroll)
                    Dim text = Data.Table.Columns(j).ColumnName
                    text = If(text Is Nothing Or text Is DBNull.Value, "", text)
                    drawingContext.DrawText( _
                      GetFormattedText( _
                          text), _
                       New Point((j - Math.Min(Data.Table.Columns.Count - 1, HorizontalScroll)) * DefaultWidth + 1, 1))
                Next
                For i = Math.Min(Data.Count - 1, VerticalScroll) To Math.Min(Data.Count - 1, maxrows + VerticalScroll)
                    For j = Math.Min(Data.Table.Columns.Count - 1, HorizontalScroll) To Math.Min(Data.Table.Columns.Count - 1, maxcols + HorizontalScroll)
                        Dim text = Data(i)(j)
                        text = If(text Is Nothing Or text Is DBNull.Value, "", text)
                        drawingContext.DrawText( _
                          GetFormattedText( _
                              text), _
                           New Point((j - Math.Min(Data.Table.Columns.Count - 1, HorizontalScroll)) * DefaultWidth, (i - Math.Min(Data.Count - 1, VerticalScroll) + 1) * DefaultHeight))
                    Next
                Next
            End If


            'drawingContext.DrawEllipse( _
            '    Brushes.Red, _
            '    Nothing, _
            '    Current, _
            '    5,
            '    5)

        End Sub


        Friend StartRow As Integer
        Friend StartColumn As Integer

        Public Property Data As DataView

        Private Current As Point
        Private Last As Point
        Private SelectionMode As Boolean = False
        Private SizingMode As Boolean = False
        Protected Overrides Sub OnMouseLeftButtonDown(ByVal e As System.Windows.Input.MouseButtonEventArgs)
            If Cursor Is DefaultCursor Then
                If e.ClickCount > 1 Then
                    Dim tmp = e.GetPosition(Me)
                    Dim x = Math.Floor(tmp.X / DefaultWidth)
                    Dim y = Math.Floor(tmp.Y / DefaultHeight)
                    Canvas.SetLeft(editingTextBox, x * DefaultWidth + 1)
                    Canvas.SetTop(editingTextBox, y * DefaultHeight + 1)
                    Dim r = New Range() With {.Row = y, .Column = x, .RowCount = 1, .ColumnCount = 1}
                    editingTextBox.Tag = r
                    r.Reset()
                    ranges.Add(r)
                    editingTextBox.Visibility = Windows.Visibility.Visible

                Else
                    Current = e.GetPosition(Me)
                    Last = Current
                    SelectionMode = True
                    InvalidateVisual()
                    If editingTextBox.Visibility = Windows.Visibility.Visible Then

                    End If
                End If
            Else
                SizingMode = True
                If Cursor Is Cursors.SizeWE Then
                    Dim tmp = e.GetPosition(Me)
                End If
            End If
        End Sub
        Protected Overrides Sub OnMouseLeftButtonUp(ByVal e As System.Windows.Input.MouseButtonEventArgs)
            SelectionMode = False
            SizingMode = False
            Cursor = DefaultCursor
        End Sub

        Public RowSizes As New List(Of SizingGroup)
        Public ColumnSizes As New List(Of SizingGroup)
        Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Input.MouseEventArgs)
            If SelectionMode And e.LeftButton = MouseButtonState.Pressed Then
                Last = e.GetPosition(Me)
                InvalidateVisual()
            Else
                If Not SizingMode Then
                    Dim tmp = e.GetPosition(Me)
                    Dim x = (tmp.X / DefaultWidth) - Math.Floor(tmp.X / DefaultWidth)
                    Dim y = (tmp.Y / DefaultHeight) - Math.Floor(tmp.Y / DefaultHeight)

                    If x = 0.0 And y <> 0.0 Then
                        Cursor = Cursors.SizeWE
                    ElseIf x <> 0.0 And y = 0.0 Then
                        Cursor = Cursors.SizeNS
                    ElseIf x = 0.0 And y = 0.0 Then
                        Cursor = Cursors.SizeAll
                    Else
                        Cursor = DefaultCursor
                    End If
                Else
                    If e.LeftButton = MouseButtonState.Pressed Then
                        If Cursor Is Cursors.SizeWE Then

                        End If
                    End If
                End If
            End If
        End Sub
        Protected Overrides Sub OnKeyDown(ByVal e As System.Windows.Input.KeyEventArgs)
            If e.Key = Key.Escape And editingTextBox.Visibility = Windows.Visibility.Visible Then
                editingTextBox.Visibility = Windows.Visibility.Collapsed
            End If
        End Sub
        'Protected Overrides Sub OnRender(ByVal dc As System.Windows.Media.DrawingContext)
        '    MyBase.OnRender(dc)
        'End Sub

        Protected Overrides Sub OnMouseWheel(ByVal e As System.Windows.Input.MouseWheelEventArgs)
            VerticalScroll = Math.Max(VerticalScroll - CInt(e.Delta / 4), 0)
            'MyBase.OnMouseWheel(e)
        End Sub

        Public Property VerticalScroll As Integer
            Get
                Return _VerticalScroll
            End Get
            Set(ByVal value As Integer)

                If value <> _VerticalScroll Then
                    _VerticalScroll = value
                    InvalidateVisual()
                End If
            End Set
        End Property

        Public Property HorizontalScroll As Integer
            Get
                Return _HorizontalScroll
            End Get
            Set(ByVal value As Integer)

                If value <> _HorizontalScroll Then
                    _HorizontalScroll = value
                    InvalidateVisual()
                End If
            End Set
        End Property
        Public ReadOnly Property MaximumScroll As Integer
            Get
                If Data Is Nothing Then
                    Return 100
                End If
                Return Math.Max(100, Data.Count + 2)
            End Get
        End Property

        Private Sub editingTextBoxLostFocus(ByVal sender As Object, ByVal e As RoutedEventArgs)
            editingTextBox.Visibility = Windows.Visibility.Collapsed
        End Sub

        Private ranges As New List(Of Range)
        Private Sub editingTextBoxKeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
            If e.Key = Key.Escape Then
                Dim r As Range = editingTextBox.Tag
                r(1, 1) = editingTextBox.Text
                editingTextBox.Visibility = Windows.Visibility.Collapsed
                InvalidateVisual()
            End If
        End Sub

        Private Function GetFormattedText(ByVal text As String) As FormattedText
            Dim result = New FormattedText( _
                text, _
                Globalization.CultureInfo.InvariantCulture, _
                Windows.FlowDirection.LeftToRight, _
                New Typeface("Calibri"), _
                12.0, _
                Brushes.Black)

            result.SetMaxTextWidths(New Double() {DefaultWidth})

            Return result
        End Function

        'Private Sub FormatClick(ByVal sender As Object, ByVal e As RoutedEventArgs)
        '    Dim fm = New FormatWindow()
        '    fm.ShowDialog()
        '    Dim x = Math.Floor(Math.Min(Current.X, Last.X) / DefaultWidth)
        '    Dim y = Math.Floor(Math.Min(Current.Y, Last.Y) / DefaultHeight)
        '    Dim x2 = Math.Floor(Math.Max(Current.X, Last.X) / DefaultWidth) + 1
        '    Dim y2 = Math.Floor(Math.Max(Current.Y, Last.Y) / DefaultHeight) + 1
        '    ranges.Add(New Range() With {
        '               .Brush = fm.SelectedBrush, _
        '               .Row = y + VerticalScroll, .RowCount = y2 - y, _
        '               .Column = x + HorizontalScroll, .ColumnCount = x2 - x})
        '    InvalidateVisual()
        'End Sub

    End Class

    Public Class Range
        Public Property Row As Integer
        Public Property Column As Integer
        Public Property RowCount As Integer
        Public Property ColumnCount As Integer

        Private datamatrix(,) As Object = Nothing
        Private datavector() As Object = Nothing
        Private data() As Object = Nothing

        Private datasimple(,) As Object = Nothing

        Friend Sub Reset()
            ReDim datasimple(RowCount - 1, ColumnCount - 1)
        End Sub

        Default Public Property Item(ByVal r As Integer, ByVal c As Integer) As Object
            Get
                Return datasimple(r - 1, c - 1)
            End Get
            Set(ByVal value As Object)
                datasimple(r - 1, c - 1) = value
            End Set
        End Property

        Public Property Brush As Brush
    End Class

    Public Class SizingGroup
        Public Property Start As Integer
        Public Property [End] As Integer
        Public Property Size As Double

        Public Shared Function Merge(ByVal size As Double, ByVal ParamArray sizes() As SizingGroup) As SizingGroup
            Return New SizingGroup() With {
                .Size = size,
                .Start = sizes.Min(Function(elt) elt.Start),
                .End = sizes.Max(Function(elt) elt.End)
            }
        End Function
    End Class
End Namespace